package com.hevery.security.core.authentication.mobile;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * @author: zhy
 * @description:
 * @date: created on 2017/11/5
 * @modified by:
 */
public class SmsCodeAuthenticationProvider implements AuthenticationProvider{

    private UserDetailsService userDetailsService;

    /**
     * 用UserDetailsService获取用户信息，获取到之后重新组装一个已经认证的Authentication
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;

        //根据手机号去读用户信息
        UserDetails user = userDetailsService.loadUserByUsername((String) authentication.getPrincipal());

        //如果获得的用户信息为空，则抛一个异常
        if(user == null){
            throw new InternalAuthenticationServiceException("无法获取用户信息");
        }

        //如果读到用户信息，那么重新构造认证信息，这时候就要使用两个参数的构造器，因为一个参数的构造函数里面我们把是否认证设置为了false，两个参数的
        //构造函数将是否认证设置为了true
        SmsCodeAuthenticationToken authenticationTokenResult = new SmsCodeAuthenticationToken(user, user.getAuthorities());

        //将之前未认证的Token里面的Details拷贝到已认证的Token中
        authenticationTokenResult.setDetails(authentication.getDetails());

        return authenticationTokenResult;
    }

    /**
     * 判断入参authentication是不是SmsCodeAuthenticationToken这个类型的，方法isAssignableFrom判断入参和调用着是否是同一个类
     * @param authentication
     * @return
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public UserDetailsService getUserDetailsService() {
        return userDetailsService;
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
}
